﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using MethodWorx.Core.DomainModel;
using MethodWorx.CMS.Web;
using System.Data.SqlClient;
using MethodWorx.CMS.Content;
using MethodWorx.CMS.Linq;
using System.Data.Linq;
using MethodWorx.Core.Linq;
using MethodWorx.CMS.Administration;
using MethodWorx.CMS.Plugins;
using MethodWorx.CMS.Membership;
using MethodWorx.CMS.Services;

namespace MethodWorx.CMS.Providers
{
    public class SqlServer : ICmsDataProvider
    {
        public Dictionary<Type, Type> services = new Dictionary<Type, Type>();

        public SqlServer()
        {
            this.AddService<IUserService, UserService>();
        }

        private class SqlServerRepositoryRegistry : IRepositoryRegistry
        {
            private CmsRequestContext requestContext;
            private string connectionString;
            

            public SqlServerRepositoryRegistry(CmsRequestContext requestContext, string connectionString)
            {
                this.requestContext = requestContext;
                this.connectionString = connectionString;
            }

            #region IRepositoryRegistry Members

            public IRepository GetRepository(Type type)
            {
                return GetRepository(this.requestContext, this.connectionString, type);
            }

            internal static IRepository GetRepository(CmsRequestContext requestContext, string connectionString, Type type)
            {
                var context = requestContext.GetInstance(() => 
                    {
                        var c = new DataContext(connectionString);
                        c.Connection.Open();
                        return c;
                    });
                
                //  next lets, get the repository
                if (type == typeof(IPageRepository))
                    return (IRepository)requestContext.GetInstance(() => new LinqPageRepository(context));

                if (type == typeof(IPageTemplateRepository))
                    return (IRepository)requestContext.GetInstance(() => new LinqPageTemplateRepository(context));

                if (type == typeof(IContentTemplateRepository))
                    return (IRepository)requestContext.GetInstance(() => new LinqContentTemplateRepository(context));

                if (type == typeof(IApplicationSettingsRepository))
                    return (IRepository)requestContext.GetInstance(() => new LinqApplicationSettingsRepository(context));

                if (type == typeof(IPluginUserDataRepository) || type == typeof(PluginUserData))
                    return (IRepository)requestContext.GetInstance(() => new LinqPluginUserDataRepository(context));

                if (type == typeof(IContentItemRepository))
                    return (IRepository)requestContext.GetInstance(() => new LinqContentItemRepository(context));

                if (type == typeof(IUserRepository) || type == typeof(LinqUser))
                    return (IRepository)requestContext.GetInstance(() => new LinqUserRepository(context));

                if (type == typeof(IPreviewSessionRepository) || type == typeof(PreviewSession))
                    return (IRepository)requestContext.GetInstance(() => new LinqPreviewSessionRepository(context));

                if (type == typeof(IContentItemRepository) || type == typeof(LinqContentItem))
                    return (IRepository)requestContext.GetInstance(() => new LinqContentItemRepository(context));

                if (type == typeof(IPageRepository) || type == typeof(LinqPage))
                    return (IRepository)requestContext.GetInstance(() => new LinqPageRepository(context));

                if (type == typeof(IPageTemplateRepository) || type == typeof(LinqPageTemplate))
                    return (IRepository)requestContext.GetInstance(() => new LinqPageTemplateRepository(context));


                //  problem, provider is not fully implemented
                throw new NotSupportedException("SqlServer provider does not support the repository: " + type.Name);
            }

            #endregion
        }


        public string ConnectionString { get; set; }
        

        #region ICmsDataProvider Members

        public void Initialize()
        {
            if (string.IsNullOrEmpty(this.ConnectionString))
                throw new ConfigurationException("Missing connection string for SqlServer provider configuration");
        }

        #endregion

        #region ICmsDataProvider Members


        public T GetService<T>()
        {
            //  firstly lets open the connection
            if(typeof(IRepository).IsAssignableFrom(typeof(T)))
                return (T)SqlServerRepositoryRegistry.GetRepository(CmsRequestContext.Current, this.ConnectionString, typeof(T));
            else
            {
                if (this.services.ContainsKey(typeof(T)))
                {
                    return (T) Activator.CreateInstance(this.services[typeof (T)], this);
                }
            }

            return default(T);
        }

        public IUnitOfWorkFactory GetUnitOfWorkFactory()
        {
            //  firstly lets open the connection
            var requestContext = CmsRequestContext.Current;
            var context = requestContext.GetInstance(() => new DataContext(this.ConnectionString));

            return requestContext.GetInstance(() => new LinqUnitOfWorkFactory(context, new SqlServerRepositoryRegistry(CmsRequestContext.Current, this.ConnectionString)));
        }

        public IRepositoryRegistry GetRepositoryRegistry()
        {
            return new SqlServerRepositoryRegistry(CmsRequestContext.Current, this.ConnectionString);
        }

        #endregion


        public void AddService<TInterface, TConcrete>() where TConcrete : TInterface
        {
            this.services.Add(typeof (TInterface), typeof (TConcrete));
        }
    }
}
